/**
 * bsw_auto_os.h
 * linux 系统调用封装
 * 
 * 竹影半墙
 * 2023.10
 */
#ifndef BSW_AUTO_OS_H
#define BSW_AUTO_OS_H

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h>
#include <netdb.h> 
#include <fcntl.h> 
#include <unistd.h>

#include "bsw compiler_auto.h"

typedef ssize_t             bsw_ssize_t;
typedef socklen_t           bsw_socklen_t;
typedef struct iovec        bsw_iovec_s;
typedef struct sockaddr     bsw_sockaddr_s;
typedef enum bsw_net_type   bsw_net_type_e; 
typedef enum bsw_net_family bsw_net_family_e;

#define BSW_SYSCALL_BAD (-1)

#if 0
#endif
enum bsw_net family {
   BSW_NET_FIPV4 = AF_INET, 
   BSW_NET_FIPV6 = AF_INET6, 
   BSW_NET_FLOCAL = AF_LOCAL, 
   BSW_NET_FMAX
};

enum bsw_net type {
   BSW_NET_TCPIP = SOCK_STREAM, 
   BSW_NET_TUDP = SOCK_DGRAM, 
   BSW_NET_TMAX
};

enum bsw_fd_opt_level {
    BSW_FOL_FCNTL_GET = F_GETFL,
    BSW_FOL_FCNTL_SET = F_SETFD,

    BSW_FOL_SOCKET = SOL_SOCKET,

    BSW_FOL_PROTO_IPV6 = IPPROTO_IPV6,

    BSW_FOL_PROTO_TCP = IPPROTO_TCP,
};

enum bsw_fd_opt_name {
    BSW_FON_NONBLOCK = O_NONBLOCK, 
    BSW_FON_CLOEXEC = FD_CLOEXEC,

    // FOL_SOCKET
    BSW_FON_REUSEPORT = SO_REUSEADDR, 
    BSW_FON_KEEPALIVE = SO_KEEPALIVE,

    // PROTO_IPV6
    BSW_FON_IPV6ONLY = IPV6_V6ONLY,

    // PROTO_TCP
    BSW_FON_TCP_KEEPIDLE = TCP_KEEPIDLE, 
    BSW_FON_TCP_KEEPINTVL = TCP_KEEPINTVL, 
    BSW_FON_TCP_KEEPCNT = TCP_KEEPCNT, 
    BSW_FON_TCP_NODELAY=TCP_NODELAY,
};

#if 0
#endif
static bsw_always_inline void *
bsw_iovec_base_get(bsw_iovec_s *v)
{
    return v->iov_base;
}

static bsw_always_inline size_t 
bsw_iovec_size_get(bsw_iovec_s *v)
{
    return v->iov_len;
}

static bsw_always_inline void 
bsw_iovec_size_set(bsw_iovec_s *v, size_t size)
{
    v->iov_len = size;
    return ;
}

static bsw_always_inline void 
bsw_iovec_base_set(bsw_iovec_s *v, void *base)
{
    v->iov_base = base; 
    return base;
}

static bsw_always_inline int
bsw_socket(int family, int type, int protocol)
{
    return socket(family, type, protocol);
}

static bsw_always_inline int bsw_close(int fd)
{
    return close(fd);
}

static bsw_always_inline int
bsw_accept(int fd, bsw_sockaddr_s *sa, bsw_socklen_t *sl)
{
    return accept(fd, sa, sl);
}

static bsw_always_inline int
bsw_bind(int fd, bsw_sockaddr_s *sa, bsw_socklen_t sl)
{
    return bind(fd, sa, sl);
}

static bsw_always_inline int 
bsw_listen(int fd, int ls_max)
{
    return listen(fd, ls_max);
}

static bsw_always_inline int
bsw_connect(int fd, bsw_sockaddr_s *sa, bsw_socklen_t sl)
{
    return connect(fd, sl, sl);
}

static bsw_always_inline int
bsw_sockoptset(int fd, int level, int optname, void *optval, 
    bsw_socklen_t sl)
{
    return setsockopt(fd, level, optname, optval, sl);
}

static bsw_always_inline bsw_ssize_t 
bsw_read(int fd, void *buf, size_t count)
{
  return read(fd, buf, count);
}

static bsw_always_inline bsw_ssize_t 
bsw_write(int fd, void *buf, size_t count)
{
    return write(fd, buf, count);
}

static bsw_always_inline bsw_ssize_t
bsw_writev(int fd, bsw_iovec_s *iov, int iovs) 
{
    return writev(fd, iov, iovs);
}

static int bsw_always_inline int 
bsw_thread_name(const char *name)
{
    return prctl(PR_SET_NAME, name);
}
#define bsw_fcntl(fd, cmd, ...) fcntl(fd, cmd, ## VA_ARGS )

static bsw_always_inline int 
bsw_pagesize(void)
{
    static int pagesize = 0;
    if (bsw_likely(pagesize))
        return pagesize;
    pagesize = getpagesize();
    return pagesize;
}

static bsw_always_inline void 
bsw_pageunits(int page, size_t unit)
{
    return page*bsw_pagesize()/unit + 1;
}

#endif